<?php
namespace Home\Controller;
use Think\Controller;

class PayController extends ParentController {
    protected function _initialize() {
    }

    /**
     * 支付宝支付接口
     * @modify 彪明 2016-05-16 创建
     */
    public function alipay() {
        $param = I('post.');

        $validateRule = array(
        	'orderNumber' => 'notnull,notempty',
            'hotel' => 'notnull,notempty,id',
        	'orderHotel' => 'notnull,notempty,id'
        );
        try {
            \Org\Util\Validate::validate($param, $validateRule);
        } catch (\Exception $e) {
	        returnJson($e->getMessage());
            return;
        }

        // 调用RPC接口获取支付信息
        $userId = session(C('USER_ID'));
        $orderNumber = $param['orderNumber'];
        $hotelId = $param['hotel'];
        $orderHotel = $param['orderHotel'];
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('ORDER_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'orderNumber' => $orderNumber,
            'userId' => $userId,
            'payPagePrice' => true,
        );
        $result = $client->detail($RPCData);

        if ($result['httpstatus'] != 200) {
	        returnJson(403, 101, $result['httpstatus'] . $result['status'], null, null, $result['info']);
	        return;
        }

        // 如果非预订状态的订单无法支付
        if ($result['data']['status'] != ORDER_BOOKED) {
            returnJson(200, 200, '该订单无法支付');
            return;
        }

        // 获取客栈支付信息
        $client = new \PHPRPC_Client(C('HOTEL_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            //'hotel' => $hotelId,
            'hotel' => $orderHotel, // 获取订单对应的客栈支付信息
        );
        $payInfoResult = $client->payInfo($RPCData);
        
        if (!is_array($payInfoResult)) {
            returnJson(403, 101, '500,500', null, null, '服务器繁忙,请稍后重试');
            return;
        }
        if ($payInfoResult['httpstatus'] != 200) {
            returnJson(403, 101, $payInfoResult['httpstatus'] . $payInfoResult['status'], null, null, $payInfoResult['info']);
            return;
        }
        $payLogic = A('Common/Pay', 'Logic');
        //$payTypeStatus = $payLogic->getPayType($hotelId, (int)$payInfoResult['data']['type']);
        $payTypeStatus = $payLogic->getPayType($orderHotel, (int)$payInfoResult['data']['type']);
        if (!$payTypeStatus['alipay']) {
            returnJson(403, 101, '500,500', null, null, '该支付功能未启用');
            return;
        }
        
        // 根据客栈支付方式是畅联代收还是商家自收,构造不同的支付信息
        $aliPayCustomConfig = C('ALIPAY');
        $alipayConfig = C('ALIPAY_CONFIG');
        if ($payTypeStatus['hotel_alipay']) {
            $aliPayCustomConfig['seller_email'] = $payInfoResult['data']['partnerPayInfo']['ali']['account'];
            $alipayConfig['partner'] = $payInfoResult['data']['partnerPayInfo']['ali']['pid'];
            $alipayConfig['key'] = $payInfoResult['data']['partnerPayInfo']['ali']['key'];
        }

        // 构造支付宝支付表单
        vendor('Alipay.AlipaySubmit');
        $paymentType = '1'; //支付类型 //必填，不能修改
        $notifyUrl = $aliPayCustomConfig['notify_url'];
        $returnUrl = $aliPayCustomConfig['return_url'] . '?no=' . $orderNumber . '&hotel=' . $hotelId;
        $showUrl = $aliPayCustomConfig['show_url'] . '?status=2&no=' . $orderNumber . '&hotel=' . $hotelId;
        $sellerEmail = $aliPayCustomConfig['seller_email'];

        $subject = '畅联科技 - 美住微预定酒店在线支付';
        $totalFee = (double)$result['data']['payPagePrice'];

        $body = $result['data']['hotelName'] . ' ' . $result['data']['roomTypeName'] . '-' . $result['data']['roomName'] . ' 入住时间:' . substr($result['data']['startDate'], 0, 10) . '至' . substr($result['data']['endDate'], 0, 10);

        $anti_phishing_key = ""; //防钓鱼时间戳 //若要使用请调用类文件submit中的query_timestamp函数
        $exter_invoke_ip = get_client_ip(); //客户端的IP地址
        //构造要请求的参数数组，无需改动

        $parameter = array(
            "service" => "alipay.wap.create.direct.pay.by.user",
            "partner" => trim($alipayConfig['partner']),
            "seller_id" => trim($alipayConfig['partner']),
            "payment_type" => $paymentType,
            "notify_url" => $notifyUrl,
            "return_url" => $returnUrl,
            "seller_email" => $sellerEmail,
            "out_trade_no" => $orderNumber,
            "subject" => $subject,
            "total_fee" => $totalFee,
            "body" => $body,
            "show_url" => $showUrl,
            "anti_phishing_key" => $anti_phishing_key,
            "exter_invoke_ip" => $exter_invoke_ip,
            "_input_charset" => trim(strtolower($alipayConfig['input_charset']))
        );
        //建立请求
        $alipaySubmit = new \AlipaySubmit($alipayConfig);
        $htmlText = $alipaySubmit->buildRequestForm($parameter, "post", "交易处理中...");

        returnJson(200, 200, $htmlText);
    }

    /**
     * 会员卡充值 支付宝支付接口
     * @modify wenhui 2018-01-18 创建
     */
    public function vipChargeAlipay() {
        $isUserLogined = parent::isLogin();
        if (empty($isUserLogined)) {
            returnJson(403, 304);
            return;
        }

        $param = I('post.');
        $validateRule = array(
            'hotel' => 'notnull,notempty,id',
            'vipUserId' => 'notnull,notempty,id',
            'vipInfoId' => 'notnull,notempty,id',
            'color' => 'notnull,notempty,id',
            'price' => 'notnull,notempty,decimal8_2',
        );
        try {
            \Org\Util\Validate::validate($param, $validateRule);
        } catch (\Exception $e) {
            returnJson($e->getMessage());
            return;
        }

        $hotel = $param['hotel'];
        $vipUserId = $param['vipUserId'];
        $vipInfoId = $param['vipInfoId'];
        $color = $param['color'];
        $price = $param['price'] > 999999.99 ? 999999.99 : $param['price'];

        $hotelName = D('HotelDetail')->getNameByHotel($hotel);
        $hotelName = isset($hotelName) ? $hotelName : '';
        // 获取客栈支付信息
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('HOTEL_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'hotel' => $hotel,
        );
        $payInfoResult = $client->payInfo($RPCData);
        if (!is_array($payInfoResult)) {
            returnJson(403, 101, '500,500', null, null, '服务器繁忙,请稍后重试');
            return;
        }
        if ($payInfoResult['httpstatus'] != 200) {
            returnJson(403, 101, $payInfoResult['httpstatus'] . $payInfoResult['status'], null, null, $payInfoResult['info']);
            return;
        }
        $payLogic = A('Common/Pay', 'Logic');
        $payTypeStatus = $payLogic->getHotelPayType($hotel, (int)$payInfoResult['data']['type']);
        if (!$payTypeStatus['hotel_alipay']) {
            returnJson(403, 101, '500,500', null, null, '该支付功能未启用');
            return;
        }

        $orderNumber = 'MZ' . getTotalMillisecond() . getRandomCode(4);
        // 客栈支付方式是商家自收
        $aliPayCustomConfig['seller_email'] = $payInfoResult['data']['partnerPayInfo']['ali']['account'];
        $alipayConfig['partner'] = $payInfoResult['data']['partnerPayInfo']['ali']['pid'];
        $alipayConfig['key'] = $payInfoResult['data']['partnerPayInfo']['ali']['key'];
        $alipayConfig['sign_type'] = strtoupper('MD5');
        $alipayConfig['input_charset'] = strtolower('utf-8');
        $alipayConfig['cacert'] = dirname(__FILE__) . '\\cacert.pem';
        $alipayConfig['transport'] = 'http';

        // 构造支付宝支付表单
        vendor('Alipay.AlipaySubmit');
        $paymentType = '1'; //支付类型 //必填，不能修改
        $notifyUrl = 'http://' . MEIZHU_BOOK_HOST . '/Home/Pay/vipChargeAlipayCallback.html';
        $returnUrl = 'http://' . MEIZHU_BOOK_HOST . '/Home/MemberPage/cardinfo.html' . '?no=' . $vipInfoId . '&hotel=' . $hotel . '&cl=' . $color . '&user=' . $vipUserId;
        $showUrl = 'http://' . MEIZHU_BOOK_HOST . '/Home/MemberPage/cardinfo.html' . '?no=' . $vipInfoId . '&hotel=' . $hotel . '&cl=' . $color . '&user=' . $vipUserId;
        $sellerEmail = $aliPayCustomConfig['seller_email'];

        $subject = '畅联科技 - 美住微预定酒店在线支付';
        $totalFee = (double)$price;

        $body = $hotelName;

        $anti_phishing_key = ""; //防钓鱼时间戳 //若要使用请调用类文件submit中的query_timestamp函数
        $exter_invoke_ip = get_client_ip(); //客户端的IP地址
        //构造要请求的参数数组，无需改动

        $parameter = array(
            "service" => "alipay.wap.create.direct.pay.by.user",
            "partner" => trim($alipayConfig['partner']),
            "seller_id" => trim($alipayConfig['partner']),
            "payment_type" => $paymentType,
            "notify_url" => $notifyUrl,
            "return_url" => $returnUrl,
            "seller_email" => $sellerEmail,
            "out_trade_no" => $orderNumber,
            "passback_params" => urlencode($vipUserId),
            "subject" => $subject,
            "total_fee" => $totalFee,
            "body" => $body,
            "show_url" => $showUrl,
            "anti_phishing_key" => $anti_phishing_key,
            "exter_invoke_ip" => $exter_invoke_ip,
            "_input_charset" => trim(strtolower($alipayConfig['input_charset']))
        );
        //建立请求
        $alipaySubmit = new \AlipaySubmit($alipayConfig);
        $htmlText = $alipaySubmit->buildRequestForm($parameter, "post", "交易处理中...");

        returnJson(200, 200, $htmlText);
    }

    /**
     * 微信成功支付回调
     * @modify 彪明 2016-05-16 创建
     */
    public function wechatPayCallback() {
        Vendor('Wechat.WxPayNotify');
        $notify = new \WxPayNotify(false);
        $data = $notify->Handle();
        if (empty($data['out_trade_no'])) {
            \Org\Util\FileLog::write('缺少订单号', 1,  'Home/AliPay');
            $notify->ReplyNotifyFail('缺少订单号');
            return;
        }

        // 检查是否支付成功
        $orderNumber = $data['out_trade_no'];
        if ($data['return_code'] != 'SUCCESS') {
            \Org\Util\FileLog::write('微信支付失败:' . $orderNumber, 1,  'Home/AliPay');
            $notify->ReplyNotifyFail('FAIL');
            return;
        }

        // 调用RPC接口改变状态
        $userId = $data['attach'];
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('ORDER_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'wechatPayData' => $data,
            'orderNumber' => $orderNumber,
            'userId' => $userId,
        );
        $result = $client->wechatPay($RPCData);
        if ($result['httpstatus'] != 200) {
            \Org\Util\FileLog::write('微信支付美住管理端RPC调用失败:' . $result['httpstatus'] . ',' . $result['status'] . ',' . $result['info'], 1,  'Home/AliPay');
            $notify->ReplyNotifyFail('FAIL');
            return;
        }
        
        $notify->ReplyNotifySuccess($wechatPayConfig['mchkey']);
    }

    /**
     * 支付宝支付回调
     * @modify 彪明 2016-05-16 创建
     */
    public function alipayCallback() {
        $param = I('request.');
        try {
            $payLogic = A('Common/Pay', 'Logic');
            $payLogic->aliPay($param);
        } catch (\Exception $e) {
            \Org\Util\FileLog::write($e->getMessage(), 1,  'Home/AliPay');
            echo 'fail';
            return;
        }
        echo 'success';
    }

    /**
     * 会员卡充值 微信成功支付回调
     * @modify wenhui 2018-01-18 创建
     */
    public function vipChargeWechatPayCallback() {
        Vendor('Wechat.WxPayNotify');
        $notify = new \WxPayNotify(false);
        $data = $notify->Handle();
        if (empty($data['out_trade_no'])) {
            \Org\Util\FileLog::write('缺少订单号', 1,  'Home/vipChargeWechatpay');
            $notify->ReplyNotifyFail('缺少订单号');
            return;
        }

        // 检查是否支付成功
        $orderNumber = $data['out_trade_no'];
        if ($data['return_code'] != 'SUCCESS') {
            \Org\Util\FileLog::write('微信支付失败:' . $orderNumber, 1,  'Home/vipChargeWechatpay');
            $notify->ReplyNotifyFail('FAIL');
            return;
        }

        // 调用RPC接口改变状态
        $vipUserId = $data['attach'];
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('ORDER_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'wechatPayData' => $data,
            'orderNumber' => $orderNumber,
            'vipUserId' => $vipUserId,
        );
        $result = $client->chargeWechatPay($RPCData);
        if ($result['httpstatus'] != 200) {
            \Org\Util\FileLog::write('微信支付美住管理端RPC调用失败:' . $result['httpstatus'] . ',' . $result['status'] . ',' . $result['info'], 1,  'Home/vipChargeWechatpay');
            $notify->ReplyNotifyFail('FAIL');
            return;
        }

        $notify->ReplyNotifySuccess($wechatPayConfig['mchkey']);
    }

    /**
     * 会员卡充值 支付宝支付回调
     * @modify wenhui 2018-01-18 创建
     */
    public function vipChargeAlipayCallback() {
        $param = I('request.');
        try {
            $payLogic = A('Common/Pay', 'Logic');
            $payLogic->chargeAliPay($param);
        } catch (\Exception $e) {
            \Org\Util\FileLog::write($e->getMessage(), 1,  'Home/vipChargeAlipay');
            echo 'fail';
            return;
        }
        echo 'success';
    }

    /**
     * 会员卡支付接口
     * @modify wenhui 2018-01-18 创建
     */
    public function vipCardPay() {
        $param = I('post.');

        $validateRule = array(
            'orderNumber' => 'notnull,notempty',
            'hotel' => 'notnull,notempty,id',
            'orderHotel' => 'notnull,notempty,id',
        );

        if (!empty($param['couponGetNo'])) {
            $validateRule['couponGetNo'] = 'notnull,notempty,ucpOrder';
        }
        try {
            \Org\Util\Validate::validate($param, $validateRule);
        } catch (\Exception $e) {
            returnJson($e->getMessage());
            return;
        }

        // 校验传过来的手机号
        $mobile = $param['mobile'];
        $mobileInSession = session(C('SMSLOGIN_MOBILE'));
        if ($mobile != $mobileInSession) {
            returnJson(403, 100);
            return;
        }

        // 校验短信验证码是否有效
        $vcode = $param['vcode'];
        try {
            $this->checkSmsVcode($vcode, 'SMSLOGIN');
        } catch (\Exception $e) {
            returnJson($e->getMessage());
            return;
        }

        // 调用RPC接口获取支付信息
        $userId = session(C('USER_ID'));
        $orderNumber = $param['orderNumber'];
        $couponGetNo = !empty($param['couponGetNo']) ? $param['couponGetNo'] : null;
        $hotelId = $param['hotel'];
        $orderHotel = $param['orderHotel'];
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('ORDER_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'orderNumber' => $orderNumber,
            'userId' => $userId,
            'payPagePrice' => true,
        );
        $result = $client->detail($RPCData);

        if ($result['httpstatus'] != 200) {
            returnJson(403, 101, $result['httpstatus'] . $result['status'], null, null, $result['info']);
            return;
        }

        // 如果非预订状态的订单无法支付
        if ($result['data']['status'] != ORDER_BOOKED) {
            returnJson(200, 200, '该订单无法支付');
            return;
        }

        // 获取客栈支付信息
        $client = new \PHPRPC_Client(C('HOTEL_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'hotel' => $orderHotel, // 获取订单对应的客栈支付信息
        );
        $payInfoResult = $client->payInfo($RPCData);

        if (!is_array($payInfoResult)) {
            returnJson(403, 101, '500,500', null, null, '服务器繁忙,请稍后重试');
            return;
        }

        if ($payInfoResult['httpstatus'] != 200) {
            returnJson(403, 101, $payInfoResult['httpstatus'] . $payInfoResult['status'], null, null, $payInfoResult['info']);
            return;
        }

        $payLogic = A('Common/Pay', 'Logic');
        $payTypeStatus = $payLogic->getPayType($orderHotel, (int)$payInfoResult['data']['type']);
        if (!$payTypeStatus['vipcardpay']) {
            returnJson(403, 101, '500,500', null, null, '该支付功能未启用');
            return;
        }

        $totalFee = (double)$result['data']['payPagePrice'];
        // 调用RPC接口进行支付
        Vendor('phpRPC.phprpc_client');
        $client = new \PHPRPC_Client(C('ORDER_RPC_URL'));
        $client->setEncryptMode(3);
        $RPCData = array(
            'flag' => C('MEIZHU_RPC_FLAG'),
            'time' => time(),
            'orderNumber' => $orderNumber,
            'couponGetNo' => $couponGetNo,
            'totalFee' => $totalFee,
            'userId' => $userId,
        );        
        $result = $client->vipCardPay($RPCData);

        if ($result['httpstatus'] != 200) {
            returnJson(403, 101, $result['httpstatus'] . $result['status'], null, null, $result['info']);
            return;
        }

        returnJson(200, 200);
    }

    /**
     * 发送短信登录验证码
     * @modify trainyao 2016-04-27    创建
     * @modify wenhui 2017-05-04 增加国际手机检验
     */
    public function smsVipPayVcode() {
        $param = I('post.');
        $areaCode = I('post.areaCode', '86', 'string');
        try {
            //\Org\Util\Validate::validate($param, $validateRule);
            \Org\Util\Validate::validate($param['mobile'], 'globalMobile', array('globalMobile' => array('function', 'checkGlobalMobile,' . $areaCode, '403,130,error')));

        } catch (\Exception $e) {
            returnJson($e->getMessage());
            return;
        }

        // 发送短信验证码
        $mobile = $param['mobile'];
        try {
            $this->sendSmsVcode($mobile, 'SMSLOGIN', $areaCode);
        } catch (\Exception $e) {
            returnJson($e->getMessage());
            return;
        }

        session(C('SMSLOGIN_MOBILE'), $mobile);

        returnJson(200, 200);
    }

    /**
     * 发送短信验证码统一逻辑
     * 方法会抛异常
     * @modify trainyao 2016-04-27    创建
     * @modify wenhui 2011-05-04    添加区号
     * @param  string   $mobile       手机号
     * @param  string   $configPrefix 配置项索引
     * @param  string   $areaCode 手机区号
     */
    private function sendSmsVcode($mobile, $configPrefix, $areaCode = '86') {
        // 校验1分钟内是否已经发送过
        $sendTime = session(C($configPrefix . '_VALIDATE_CODE_SEND_TIME'));
        if (!empty($sendTime) && !isOverMinute($sendTime, C('VALIDATE_CODE_RESENT_MINUTE'))) {
            throw new \Exception('403,200', 200);
            return;
        }

        // 生成随机数字发送
        $vcode = getRandomNumber(4);
        if ($areaCode == '86') {
            $smsUtil = new \Org\Util\Sms();
            $smsSendResult = $smsUtil->sendVocode($mobile, $vcode);
        } else {
            $smsUtil = new \Org\Util\yunPian();
            $smsSendResult = $smsUtil->sendVcode($areaCode, $mobile, $vcode);
        }

        if (empty($smsSendResult)) {
            throw new \Exception('500,507', 507);
            return;
        }

        $time = time();
        session(C($configPrefix . '_VALIDATE_CODE'), $vcode);
        session(C($configPrefix . '_VALIDATE_CODE_SEND_TIME'), $time);
    }

    /**
     * 校验短信验证码逻辑
     * 方法会抛异常
     * @modify trainyao 2016-04-27 创建
     * @param  string   $vcode     短信验证码
     * @param  string   $configPrefix     配置项前缀,用于检测不同功能模块
     * @return mixin                校验失败抛异常
     */
    private function checkSmsVcode($vcode, $configPrefix) {
        // 校验验证码,session是否有值,验证码是否已经过期
        $vcodeInSession = session(C($configPrefix . '_VALIDATE_CODE'));
        $vcodeSendTime = session(C($configPrefix . '_VALIDATE_CODE_SEND_TIME'));
        if (empty($vcodeInSession) || empty($vcodeSendTime)) {
            throw new \Exception('403,100', 100);
            return;
        }
        if (isOverMinute($vcodeSendTime, C('VALIDATE_CODE_OUTDATE_MINUTE'))) {
            throw new \Exception('403,201', 201);
            return;
        }
        if ($vcode != $vcodeInSession) {
            throw new \Exception('403,202', 202);
            return;
        }
    }
}
